home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Utilities / Ph 1.1.1 / Lib / oop.c < prev    next >
Encoding:
Text File  |  1991-10-14  |  33.3 KB  |  1,123 lines  |  [TEXT/MPS ]

  1. /*_____________________________________________________________________
  2.  
  3.       oop.c - Reusable Object-Oriented Window and Command Management Module.
  4.     
  5.     John Norstad
  6.     Academic Computing and Network Services
  7.     Northwestern University
  8.     j-norstad@nwu.edu
  9.     
  10.     Copyright © Northwestern University, 1991.
  11.     
  12.     This module defines a superclass for Mac windows. It defines methods 
  13.     for handling the standard window events (periodic, click, key, update, 
  14.     activate, deactivate, grow, zoom, close, and command).
  15.     
  16.     The class supports normal document windows and both modeless and 
  17.     movable modal dialog windows.
  18.     
  19.     In most cases the methods are defined to do nothing for document 
  20.     windows, and to do the usual processing for dialog windows (the equivalent
  21.     of the "DialogSelect" toolbox routine). For document windows you will want 
  22.     to override most if not all of these methods. For dialog windows the 
  23.     superclass methods will often suffice.
  24.     
  25.     Commands are handled by first dispatching a DoCommand message to
  26.     the top window object. If the top window object cannot handle the
  27.     command, a list of registered command handlers is called. A function
  28.     is exported which permits callers to register command handlers.
  29.     
  30.     The module also exports an event handling function which takes
  31.     care of dispatching events by sending messages to the appropriate
  32.     window objects. The typical main event loop consists of repeated
  33.     calls to this function.
  34.     
  35.     The module's initialization function initializes itself and also takes
  36.     care of the usual memory and toolbox initialization tasks.
  37.     
  38.     Message dispatching is accomplished via dispatch tables, which are
  39.     structs of type "oop_Dispatch" containing pointers to method functions.  
  40.     Each subclass has its own method dispatch table.
  41.     
  42.     For example, if "dispatch" is a pointer to a dispatch table, and "w" 
  43.     is a pointer to a window record, then
  44.     
  45.         (*dispatch->DoUpdate)(w)
  46.         
  47.     sends a "DoUpdate" message to the window "w".
  48.     
  49.     Each subclass must provide a dispatch table for that subclass. 
  50.     Method overriding is accomplished by storing pointers to subclass 
  51.     methods in the dispatch table. The superclass methods can be used by 
  52.     storing pointers to the superclass methods in the dispatch table.
  53.     
  54.     For example, in module "mywind.c", you might declare a dispatch
  55.     table as follows:
  56.     
  57.         static oop_Dispatch    dispatch = {
  58.                                         oop_DoPeriodic,
  59.                                         mywind_DoClick,
  60.                                         mywind_DoKey,
  61.                                         mywind_DoUpdate,
  62.                                         oop_DoActivate,
  63.                                         oop_DoDeactivate,
  64.                                         mywind_DoGrow,
  65.                                         mywind_DoZoom,
  66.                                         mywind_DoClose,
  67.                                         mywind_DoCommand
  68.                                     };
  69.  
  70.     In this example the "mywind" subclass has overridden all but the
  71.     DoPeriodic, DoActivate, and DoDeactivate methods.
  72.     
  73.     Inherited methods can be called from within a subclass method by
  74.     simply calling the appropriate function.  For example, in the 
  75.     "mywind" class, the mywind_DoClose method can (and usually does)
  76.     call the oop_DoClose method.
  77.     
  78.     Instance variables for a window object are stored in a separate struct of
  79.     type "WindObj". A handle to this struct is stored in the window record 
  80.     "refCon" field.  In addition to the instance variables, this struct also
  81.     contains a pointer to the method dispatch table for the subclass to
  82.     which the window belongs, plus a handle to subclass instance 
  83.     variables for the window object.
  84.     
  85.     Note the difference between the instance variable structs and the
  86.     dispatch table structs: Each individual window has its own instance
  87.     variables, while there is only a single dispatch table per window 
  88.     subclass. Also, the dispatch table struct definition "oop_Dispatch" 
  89.     is exported from the oop.c module, while the instance variable struct
  90.     definition "WindObj" is private.
  91.     
  92.     Here's a picture:
  93.     
  94.     WindowRecord      WindObj            Type defined by subclass
  95.    ------------    -----------         ----------
  96.    |             |    |Instance |         |Subclass|
  97.     |   refCon |--->|Vars     |    |--->|Instance|
  98.     |          |    |         |    |    |Vars    |
  99.     ------------    |    info |-----    ----------
  100.                     |dispatch |-----
  101.                          -----------    |    oop_Dispatch
  102.                                   |    ------------
  103.                                   |    |          |---> method
  104.                                   |--->|          |---> method
  105.                                                     |          |---> method
  106.                                                     ------------
  107.  
  108. ____________________________________________________________________*/
  109.  
  110. /*_____________________________________________________________________
  111.  
  112.     Header Files.
  113. _____________________________________________________________________*/
  114.  
  115. #pragma load "precompile"
  116. #include "utl.h"
  117. #include "oop.h"
  118.  
  119. /*_____________________________________________________________________
  120.  
  121.     Defines.
  122. _____________________________________________________________________*/
  123.  
  124. #define cutCmd            3        /* item number of edit menu cut command */
  125. #define copyCmd        4        /* item number of edit menu copy command */
  126. #define pasteCmd        5        /* item number of edit menu paste command */
  127. #define clearCmd        6        /* item number of edit menu clear command */
  128.  
  129. #define dragSlop        4        /* window drag slop in pixels */
  130.  
  131. /*_____________________________________________________________________
  132.  
  133.     Types.
  134. _____________________________________________________________________*/
  135.     
  136. typedef struct WindOjb {
  137.  
  138.     /* Class instance variables. */
  139.  
  140.     short                kind;                /* kind of window */
  141.     Boolean            dialog;            /* true if dialog */
  142.     Boolean            modal;            /* true if movable modal dialog */
  143.     Boolean            moved;            /* true if moved or size changed */
  144.     RgnHandle        ibeamRgn;        /* ibeam region */
  145.     short                defaultBtn;        /* item number of default button */
  146.     short                cancelBtn;        /* item number of cancel button */
  147.     short                itemHit;            /* item number of item hit */
  148.     
  149.     /* Other information. */
  150.     
  151.     Handle            info;                /* handle to subclass instance vars */
  152.     oop_Dispatch    *dispatch;        /* pointer to method dispatch table */    
  153.     
  154. } WindObj;
  155.  
  156. /*______________________________________________________________________
  157.  
  158.     Variables.
  159. _____________________________________________________________________*/
  160.  
  161. EventRecord            Event;                    /* the current event */
  162.  
  163. static FCommand    (**CmdHandlers)[];    /* handle to array of command handlers */
  164. static short        numCmdHandlers = 0;    /* number of command handlers */
  165.  
  166. static short        AppleMenuID;            /* apple menu id */
  167. static short        LastAppleMenuItem;    /* item number of last apple menu item */
  168. static short        FileMenuID;                /* file menu id */
  169. static short        CloseMenuItem;            /* item number of close command */
  170. static short        EditMenuID;                /* edit menu id */
  171. static short        SelectAllItem;            /* item number of select all command,
  172.                                                             or 0 if none. */
  173. static FPeriodic    DoPeriodic;                /* ptr to global DoPeriodic function */
  174. static FDisk        DoDisk;                    /* ptr to global DoDisk function */
  175. static Rect            DragRect;                /* window drag rectangle */
  176. static CursHandle    IBeamHandle;            /* handle to ibeam cursor */
  177. static Boolean        InForeground = true;    /* true if in foreground */
  178.  
  179. /*_____________________________________________________________________
  180.  
  181.     GetWindObj - Get Window Object.
  182.     
  183.     Entry:    w = pointer to window record.
  184.     
  185.     Exit:        function result = handle to window object.
  186. _____________________________________________________________________*/
  187.  
  188. static WindObj **GetWindObj (WindowPtr w)
  189.  
  190. {
  191.     return (WindObj**)((WindowPeek)w)->refCon;
  192. }
  193.  
  194. /*_____________________________________________________________________
  195.  
  196.     OutlineDefaultButton - Outline Default Button.
  197.  
  198.     Entry:    theWindow = pointer to dialog window.
  199.                 itemNo = item number of outline useritem.
  200.                 
  201.     This routine is for use as a useritem handler to outline default
  202.     buttons in dialogs.
  203. _____________________________________________________________________*/
  204.  
  205. pascal void OutlineDefaultButton (WindowPtr theWindow, short itemNo)
  206.  
  207. {
  208.     short                itemType;        /* item type */
  209.     Handle            item;                /* handle to item */
  210.     Rect                box;                /* item rectangle */
  211.  
  212.     GetDItem(theWindow, itemNo, &itemType, &item, &box);
  213.     InsetRect(&box, -4, -4);
  214.     PenSize(3, 3);
  215.     FrameRoundRect(&box, 16, 16);
  216.     PenSize(1, 1);
  217. }    
  218.  
  219. /*_____________________________________________________________________
  220.  
  221.     oop_GetWindKind - Get Window Kind.
  222.     
  223.     Entry:    w = pointer to window record.
  224.     
  225.     Exit:        function result = window kind.
  226. _____________________________________________________________________*/
  227.  
  228. short oop_GetWindKind (WindowPtr w)
  229.  
  230. {
  231.     if (!w) {
  232.         return noWind;
  233.     } else if (((WindowPeek)w)->windowKind < 0) {
  234.         return daWind;
  235.     } else {
  236.         return (**(WindObj**)((WindowPeek)w)->refCon).kind;
  237.     }
  238. }
  239.  
  240. /*_____________________________________________________________________
  241.  
  242.     oop_GetWindInfo - Get Window Info.
  243.     
  244.     Entry:    w = pointer to window record.
  245.     
  246.     Exit:        function result = handle to window subclass instance variables.
  247. _____________________________________________________________________*/
  248.  
  249. Handle oop_GetWindInfo (WindowPtr w)
  250.  
  251. {
  252.     return (**(WindObj**)((WindowPeek)w)->refCon).info;
  253. }
  254.  
  255. /*_____________________________________________________________________
  256.  
  257.     oop_GetWindItemHit - Get Window ItemHit Instance Variable.
  258.     
  259.     Entry:    w = pointer to window record.
  260.     
  261.     Exit:        function result = itemHit instance variable.
  262. _____________________________________________________________________*/
  263.  
  264. short oop_GetWindItemHit (WindowPtr w)
  265.  
  266. {
  267.     return (**(WindObj**)((WindowPeek)w)->refCon).itemHit;
  268. }
  269.  
  270. /*_____________________________________________________________________
  271.  
  272.     oop_ClearWindItemHit - Clear Window ItemHit Instance Variable.
  273.     
  274.     Entry:    w = pointer to window record.
  275. _____________________________________________________________________*/
  276.  
  277. void oop_ClearWindItemHit (WindowPtr w)
  278.  
  279. {
  280.     (**(WindObj**)((WindowPeek)w)->refCon).itemHit = 0;
  281. }
  282.  
  283. /*_____________________________________________________________________
  284.  
  285.     oop_GetWindIbeamRgn - Get Window IbeamRgn Instance Variable.
  286.     
  287.     Entry:    w = pointer to window record.
  288.     
  289.     Exit:        function result = ibeamRgn instance varialbe.
  290. _____________________________________________________________________*/
  291.  
  292. RgnHandle oop_GetWindIbeamRgn (WindowPtr w)
  293.  
  294. {
  295.     return (**(WindObj**)((WindowPeek)w)->refCon).ibeamRgn;
  296. }
  297.  
  298. /*_____________________________________________________________________
  299.  
  300.     oop_Moved - Find Out if Window Has Moved.
  301.     
  302.     Entry:    w = pointer to window record.
  303.     
  304.     Exit:        function result = true if window has moved or changed size.
  305. _____________________________________________________________________*/
  306.  
  307. Boolean oop_Moved (WindowPtr w)
  308.  
  309. {
  310.     return (**(WindObj**)((WindowPeek)w)->refCon).moved;
  311. }
  312.  
  313. /*_____________________________________________________________________
  314.  
  315.     oop_InForeground - Determine Whether We Are in the Foreground.
  316. _____________________________________________________________________*/
  317.  
  318. Boolean oop_InForeground (void)
  319.  
  320. {
  321.     return InForeground;
  322. }
  323.  
  324. /*_____________________________________________________________________
  325.  
  326.     Init - Complete Initialization.
  327. _____________________________________________________________________*/
  328.  
  329. #pragma segment init
  330.  
  331. static void Init (void)
  332.  
  333. {
  334.     Rect                        screenRect;    /* screen rectangle */
  335.     ProcessSerialNumber    myPsn;        /* my psn */
  336.     ProcessSerialNumber    frontPsn;    /* front process psn */
  337.     EventRecord                dummy;        /* dummy event record */
  338.     
  339.     /* Initialize the toolbox. */
  340.     
  341.     InitGraf(&qd.thePort);                /* initialize quickdraw */
  342.     InitFonts();                            /* initialize font manager */
  343.     FlushEvents(everyEvent, 0);        /* drain event queue */
  344.     InitWindows();                            /* initialize window manager */
  345.     InitMenus();                            /* initialize menu manager */
  346.     TEInit();                                /* initialize textedit */
  347.     InitDialogs(nil);                        /* initialize dialog manager */
  348.     InitCursor();                            /* initialize cursor */
  349.     
  350.     /* Initialize the command handler array. */
  351.     
  352.     CmdHandlers = (FCommand(**)[])NewHandle(0);
  353.     
  354.     /* Initialize the drag rect. */
  355.     
  356.     screenRect = qd.screenBits.bounds;
  357.     SetRect(&DragRect, dragSlop, titleBarHeight + dragSlop, 
  358.         screenRect.right - dragSlop, screenRect.bottom - dragSlop);
  359.         
  360.     /* Get the ibeam cursor. */
  361.         
  362.     IBeamHandle = GetCursor(iBeamCursor);
  363.     
  364.     /* Figure out whether we're in the foreground or background. */
  365.     
  366.     if (utl_GestaltFlag(gestaltOSAttr, gestaltLaunchCanReturn) &&
  367.         utl_GestaltFlag(gestaltOSAttr, gestaltLaunchFullFileSpec) &&
  368.         utl_GestaltFlag(gestaltOSAttr, gestaltLaunchControl)) {
  369.         GetCurrentProcess(&myPsn);
  370.         GetFrontProcess(&frontPsn);
  371.         SameProcess(&myPsn, &frontPsn, &InForeground);
  372.     }
  373.     
  374.     /* Call EventAvail a few times to force any windows to initally
  375.         appear in the foreground.  See TN 180. */
  376.     
  377.     EventAvail(everyEvent, &dummy);
  378.     EventAvail(everyEvent, &dummy);
  379. }
  380.  
  381. #pragma segment Main
  382.  
  383. /*_____________________________________________________________________
  384.  
  385.     oop_Init - Initialize.
  386.     
  387.     Entry:    appleMenuID = apple menu id.
  388.                 lastAppleMenuItem = item number of last user item in apple menu.
  389.                 fileMenuID = file menu id.
  390.                 closeMenuItem = item number of close command in file menu,
  391.                     or 0 if none.
  392.                 editMenuID = edit menu id.
  393.                 selectAllItem = item number of select all command in edit menu,
  394.                     or 0 if none.
  395.                 doPeriodic = pointer to global DoPeriodic function.
  396.                 doDisk = pointer to global disk insertion event handler, or nil
  397.                     if none.
  398.                 extraMasterPtrBlocks = number of extra master pointer blocks
  399.                     to allocate.
  400.                 extraStackSpace = number of extra bytes of stack space to
  401.                     allocate.
  402. _____________________________________________________________________*/
  403.  
  404. void oop_Init (short appleMenuID, short lastAppleMenuItem, 
  405.     short fileMenuID, short closeMenuItem,
  406.     short editMenuID, short selectAllItem, 
  407.     FPeriodic doPeriodic, FDisk doDisk,
  408.     long extraMasterPtrBlocks, long extraStackSpace)
  409.  
  410. {
  411. #ifndef THINK_C
  412.     extern void _DataInit();
  413. #endif
  414.  
  415.     short            i;                    /* loop index */
  416.  
  417. #ifndef THINK_C
  418.     UnloadSeg(_DataInit);
  419. #endif
  420.     
  421.     /* Copy parameters to global variables. */
  422.     
  423.     AppleMenuID = appleMenuID;
  424.     LastAppleMenuItem = lastAppleMenuItem;
  425.     FileMenuID = fileMenuID;
  426.     CloseMenuItem = closeMenuItem;
  427.     EditMenuID = editMenuID;
  428.     SelectAllItem = selectAllItem;
  429.     DoPeriodic = doPeriodic;
  430.     DoDisk = doDisk;
  431.     
  432.     /* Initialize memory. */
  433.     
  434.     SetApplLimit(GetApplLimit() - extraStackSpace);
  435.     MaxApplZone();
  436.     for (i = 0; i < extraMasterPtrBlocks; i++) MoreMasters();
  437.     
  438.     /* Complete initialization. */
  439.     
  440.     Init();
  441. }
  442.  
  443. /*_____________________________________________________________________
  444.  
  445.     oop_RegisterCommandHandler - Register Command Handler.
  446.     
  447.     Entry:    handler = command handler.
  448. _____________________________________________________________________*/
  449.  
  450. void oop_RegisterCommandHandler (FCommand handler)
  451.  
  452. {
  453.     numCmdHandlers++;
  454.     SetHandleSize((Handle)CmdHandlers, numCmdHandlers*sizeof(FCommand));
  455.     (**CmdHandlers)[numCmdHandlers-1] = handler;
  456. }
  457.  
  458. /*_____________________________________________________________________
  459.  
  460.     oop_NewWindow - Initialize New Document Window.
  461.     
  462.     Entry:    w = pointer to window record.
  463.                 kind = kind of window.
  464.                 info = handle to window info.
  465.                 dispatch = pointer to method dispatch table.
  466. _____________________________________________________________________*/
  467.  
  468. void oop_NewWindow (WindowPtr w, short kind, Handle info, oop_Dispatch *dispatch)
  469.  
  470. {
  471.     WindObj        **wobj;            /* handle to new window object */
  472.     
  473.     wobj = (WindObj**)NewHandle(sizeof(WindObj));
  474.     ((WindowPeek)w)->refCon = (long)wobj;
  475.     (**wobj).kind = kind;
  476.     (**wobj).dialog = false;
  477.     (**wobj).modal = false;
  478.     (**wobj).moved = false;
  479.     (**wobj).ibeamRgn = NewRgn();
  480.     (**wobj).info = info;
  481.     (**wobj).dispatch = dispatch;
  482.     if (InForeground) (*DoPeriodic)(FrontWindow());
  483. }
  484.  
  485. /*_____________________________________________________________________
  486.  
  487.     oop_NewDialog - Initialize New Dialog Window.
  488.     
  489.     Entry:    d = pointer to dialog record.
  490.                 kind = kind of window.
  491.                 info = handle to window info.
  492.                 dispatch = pointer to method dispatch table.
  493.                 modal = true if movable modal dialog.
  494.                 defaultBtn = item number of default button, or 0 if none.
  495.                 cancelBtn = item number of cancel button, or 0 if none.
  496.                 
  497.     If the dialog contains a default button, an extra userItem is appended
  498.     to the end of the dialog item list to outline the default button 
  499.     (see IM I-427).
  500. _____________________________________________________________________*/
  501.  
  502. void oop_NewDialog (WindowPtr d, short kind, Handle info, oop_Dispatch *dispatch,
  503.     Boolean modal, short defaultBtn, short cancelBtn)
  504.  
  505. {
  506.     WindObj        **wobj;            /* handle to window object */
  507.     Handle        items;            /* handle to item list */
  508.     long            size;                /* size of item list */
  509.     short            itemType;        /* default button item type */
  510.     Handle        item;                /* handle to default button control */
  511.     Rect            box;                /* default button rectangle */
  512.  
  513.     wobj = (WindObj**)NewHandle(sizeof(WindObj));
  514.     ((WindowPeek)d)->refCon = (long)wobj;
  515.     (**wobj).kind = kind;
  516.     (**wobj).dialog = true;
  517.     (**wobj).modal = modal;
  518.     (**wobj).moved = false;
  519.     (**wobj).ibeamRgn = utl_BuildDialogIBeamRgn(d);
  520.     (**wobj).defaultBtn = defaultBtn;
  521.     (**wobj).cancelBtn = cancelBtn;
  522.     (**wobj).itemHit = 0;
  523.     (**wobj).info = info;
  524.     (**wobj).dispatch = dispatch;
  525.     if (defaultBtn) {
  526.         items = ((DialogPeek)d)->items;
  527.         size = GetHandleSize(items);
  528.         SetHandleSize(items, size+14);
  529.         (**(short**)items)++;
  530.         *(ProcPtr*)(*items+size) = (ProcPtr)OutlineDefaultButton;
  531.         GetDItem(d, defaultBtn, &itemType, &item, &box);
  532.         BlockMove(&box, *items+size+4, 8);
  533.         *(*items+size+12) = userItem | itemDisable;
  534.         *(*items+size+13) = 0;
  535.     }
  536.     if (InForeground) (*DoPeriodic)(FrontWindow());
  537. }
  538.  
  539. /*_____________________________________________________________________
  540.  
  541.     oop_DoPeriodic - Periodic Method.
  542.     
  543.     Entry:    w = pointer to window record.
  544.     
  545.     This method changes the cursor to an ibeam if the mouse is over the
  546.     ibeam region, otherwise it changes the cursor to an arrow.
  547.     
  548.     For dialogs, it also calls TEIdle to blink the insertion point.
  549. _____________________________________________________________________*/
  550.  
  551. void oop_DoPeriodic (WindowPtr w)
  552.  
  553. {
  554.     WindObj        **wobj;        /* handle to window object */
  555.     Point            where;        /* current mouse location */
  556.  
  557.     wobj = GetWindObj(w);
  558.     GetMouse(&where);
  559.     SetCursor(PtInRgn(where, (**wobj).ibeamRgn) ? *IBeamHandle : &qd.arrow);
  560.     if ((**wobj).dialog) TEIdle(((DialogPeek)w)->textH);
  561. }
  562.  
  563. /*_____________________________________________________________________
  564.  
  565.     oop_DoClick - Mouse Down Event Handler Method.
  566.     
  567.     Entry:    w = pointer to window record.
  568.                 where = mouse click location in local coordinates.
  569.                 modifiers = modifiers from event record.
  570.                 
  571.     For document windows this method does nothing. 
  572.     
  573.     For dialog windows the method calls DialogSelect to handle the event.
  574.     If an enabled item is selected, the itemHit instance variable is
  575.     set to the item number of the selected item.
  576. _____________________________________________________________________*/
  577.  
  578. void oop_DoClick (WindowPtr w, Point where, short modifiers)
  579.  
  580. {
  581. #pragma unused (where)
  582. #pragma unused (modifiers)
  583.  
  584.     WindObj                **wobj;        /* handle to window object */
  585.     DialogPtr            dlog;            /* pointer to dialog record */
  586.     short                    itemHit;        /* item number of item hit */
  587.  
  588.     wobj = GetWindObj(w);
  589.     if (!(**wobj).dialog) return;
  590.     if (DialogSelect(&Event, &dlog, &itemHit)) (**wobj).itemHit = itemHit;
  591. }
  592.  
  593. /*_____________________________________________________________________
  594.  
  595.     oop_DoKey - Key Down and AutoKey Event Handler Method.
  596.     
  597.     Entry:    w = pointer to window record.
  598.                 key = ascii code of key.
  599.                 modifiers = modifiers from event record.
  600.                 
  601.     For document windows this method does nothing. 
  602.     
  603.     For dialog windows the method first checks to see if a special key
  604.     was typed:
  605.     
  606.         Return or Enter: Treated same as click on default button.
  607.         Escape or Cmd-period: Treated same as click on cancel button.
  608.         
  609.     If a special key was typed, the button is flashed and the itemHit
  610.     instance variable is set to the item number of the button.
  611.     
  612.     If the key is not special, DialogSelect is called to handle the event.
  613. _____________________________________________________________________*/
  614.  
  615. void oop_DoKey (WindowPtr w, char key, short modifiers)
  616.  
  617. {
  618.     WindObj                **wobj;        /* handle to window object */
  619.     DialogPtr            dlog;            /* pointer to dialog record */
  620.     short                    itemHit;        /* item number of item hit */
  621.  
  622.     wobj = GetWindObj(w);
  623.     if (!(**wobj).dialog) return;
  624.     if ((**wobj).itemHit = utl_CheckSpecialDialogKey(w, key, modifiers, 
  625.         (**wobj).defaultBtn, (**wobj).cancelBtn)) return;
  626.     DialogSelect(&Event, &dlog, &itemHit);
  627. }
  628.  
  629. /*_____________________________________________________________________
  630.  
  631.     oop_DoUpdate - Update Event Handler Method.
  632.     
  633.     Entry:    w = pointer to window record.
  634.     
  635.     For document windows the window is erased. This method is seldom used for
  636.     document windows, since they almost always contain something that needs to
  637.     be drawn!
  638.     
  639.     For dialog windows the dialog is drawn and the default button, if any,
  640.     is outlined.
  641. _____________________________________________________________________*/
  642.  
  643. void oop_DoUpdate (WindowPtr w)
  644.  
  645. {
  646.     WindObj        **wobj;                /* handle to window object */
  647.  
  648.     wobj = GetWindObj(w);
  649.     EraseRect(&w->portRect);
  650.     if ((**wobj).dialog) DrawDialog(w);
  651. }
  652.  
  653. /*_____________________________________________________________________
  654.  
  655.     oop_DoActivate - Activate Event Handler Method.
  656.     
  657.     Entry:    w = pointer to window record.
  658.     
  659.     For document windows this method does nothing.
  660.     
  661.     For dialog windows DialogSelect is called to handle the event.
  662. _____________________________________________________________________*/
  663.  
  664. void oop_DoActivate (WindowPtr w)
  665.  
  666. {
  667.     WindObj                **wobj;        /* handle to window object */
  668.     DialogPtr            dlog;            /* pointer to dialog record */
  669.     short                    itemHit;        /* item number of item hit */
  670.  
  671.     wobj = GetWindObj(w);
  672.     if (!(**wobj).dialog) return;
  673.     DialogSelect(&Event, &dlog, &itemHit);
  674. }
  675.  
  676. /*_____________________________________________________________________
  677.  
  678.     oop_DoDeactivate - Deactivate Event Handler Method.
  679.     
  680.     Entry:    w = pointer to window record.
  681.     
  682.     For document windows this method does nothing.
  683.     
  684.     For dialog windows DialogSelect is called to handle the event.
  685. _____________________________________________________________________*/
  686.  
  687. void oop_DoDeactivate (WindowPtr w)
  688.  
  689. {
  690.     WindObj                **wobj;        /* handle to window object */
  691.     DialogPtr            dlog;            /* pointer to dialog record */
  692.     short                    itemHit;        /* item number of item hit */
  693.  
  694.     wobj = GetWindObj(w);
  695.     if (!(**wobj).dialog) return;
  696.     DialogSelect(&Event, &dlog, &itemHit);
  697. }
  698.  
  699. /*_____________________________________________________________________
  700.  
  701.     oop_DoGrow - Window Grow Method.
  702.     
  703.     Entry:    w = pointer to window record.
  704.                 where = mouse location.
  705.                 
  706.     This method does nothing.
  707. _____________________________________________________________________*/
  708.  
  709. void oop_DoGrow (WindowPtr w, Point where)
  710.  
  711. {
  712. #pragma unused (w)
  713. #pragma unused (where)
  714. }
  715.  
  716. /*_____________________________________________________________________
  717.  
  718.     oop_DoZoom - Window Zoom Method.
  719.     
  720.     Entry:    w = pointer to window record.
  721.                 where = mouse location.
  722.                 partCode = inZoomIn or inZoomOut part code.
  723.                 
  724.     This method does nothing.
  725. _____________________________________________________________________*/
  726.  
  727. void oop_DoZoom (WindowPtr w, Point where, short partCode)
  728.  
  729. {
  730. #pragma unused (w)
  731. #pragma unused (where)
  732. #pragma unused (partCode)
  733. }
  734.  
  735. /*_____________________________________________________________________
  736.  
  737.     oop_DoClose - Window Close Method.
  738.     
  739.     Entry:    w = pointer to window record.
  740.     
  741.     This method disposes the WindObj record and the window itself.
  742. _____________________________________________________________________*/
  743.  
  744. void oop_DoClose (WindowPtr w)
  745.  
  746. {
  747.     WindObj            **wobj;        /* handle to window object */
  748.     
  749.     wobj = GetWindObj(w);
  750.     DisposeRgn((**wobj).ibeamRgn);
  751.     if ((**wobj).dialog) {
  752.         DisposDialog(w);
  753.     } else {
  754.         DisposeWindow(w);
  755.     }
  756.     DisposHandle((Handle)wobj);
  757.     if (InForeground) (*DoPeriodic)(FrontWindow());
  758. }
  759.  
  760. /*_____________________________________________________________________
  761.  
  762.     oop_DoCommand - Command Handler Method.
  763.     
  764.     Entry:    w = pointer to window record.
  765.                 theMenu = menu index.
  766.                 theItem = item index.
  767.                 
  768.     Exit:        function result = true if command handled.
  769.                 
  770.     For document windows this method does nothing.
  771.     
  772.     For dialog windows the Edit menu commands cut, copy, paste, clear,
  773.     and select all (if present) are handled.
  774. _____________________________________________________________________*/
  775.  
  776. #pragma segment command
  777.  
  778. Boolean oop_DoCommand (WindowPtr w, short theMenu, short theItem)
  779.  
  780. {
  781.     WindObj            **wobj;        /* handle to window object */
  782.     TEHandle            textH;        /* handle to active TextEdit record */
  783.  
  784.     wobj = GetWindObj(w);
  785.     if (!(**wobj).dialog) return false;
  786.     textH = ((DialogPeek)w)->textH;
  787.     if (theMenu != EditMenuID) return false;
  788.     if (theItem == SelectAllItem) {
  789.         TESetSelect(0, 0x7fff, textH);
  790.         return true;
  791.     } else {
  792.         switch (theItem) {
  793.             case cutCmd:
  794.             case copyCmd:
  795.                 if (theItem == cutCmd) 
  796.                     TECut(textH); 
  797.                 else 
  798.                     TECopy(textH);
  799.                 ZeroScrap();
  800.                 TEToScrap();
  801.                 return true;
  802.             case pasteCmd:
  803.                 TEFromScrap();
  804.                 TEPaste(textH);
  805.                 return true;
  806.             case clearCmd:
  807.                 TEDelete(textH);
  808.                 return true;
  809.         }
  810.     }
  811.     return false;
  812. }
  813.  
  814. #pragma segment Main
  815.  
  816. /*_____________________________________________________________________
  817.  
  818.     DispatchCommand - Dispatch a Command.
  819.     
  820.     Entry:    top = pointer to top window record.
  821.                 kind = top window kind.
  822.                 dispatch = pointer to method dispatch table for top
  823.                     window object.
  824.                 mResult = 16/menu number, 16/item number.
  825.                 
  826.     This function handles all commands for DAs.
  827.     
  828.     The Close command is handled by dispatching a DoClose messaage to the
  829.     top window object.
  830.     
  831.     All other commands are processed as follows:
  832.     
  833.     If there is a top window and it is not a DA window, then a DoCommand
  834.     message is dispatched to the top window.  The DoCommand method returns
  835.     true if the command was processed, in which case we're done.  Otherwise,
  836.     the registered DoCommand methods are given an opportunity to process the 
  837.     command, in the order in which they were registered. For these later
  838.     calls, nil is passed for the window pointer parameter.
  839.     
  840.     Note that it is possible for a DoCommand method to be called twice -
  841.     once for the top window, and then again later because it is in the
  842.     command handler list.
  843. _____________________________________________________________________*/
  844.  
  845. static void DispatchCommand (WindowPtr top, short kind,
  846.     oop_Dispatch *dispatch, unsigned long mResult)
  847.  
  848. {
  849.     short                theMenu;            /* menu number */
  850.     short                theItem;            /* item number */
  851.     Str255            daName;            /* da name */
  852.     GrafPtr            savePort;        /* saved grafPort */
  853.     Boolean            callHandlers;    /* true to pass command to command handlers */
  854.     short                i;                    /* loop index */
  855.     
  856.     theMenu = (mResult >> 16) & 0xFFFF;
  857.     theItem = mResult & 0xFFFF;
  858.     callHandlers = true;
  859.     if (theMenu == AppleMenuID && theItem > LastAppleMenuItem) {
  860.         GetItem(GetMHandle(AppleMenuID), theItem, daName);
  861.         GetPort(&savePort);
  862.         (void) OpenDeskAcc(daName);
  863.         SetPort(savePort);
  864.         callHandlers = false;
  865.     } else if (theMenu == FileMenuID && theItem == CloseMenuItem && top) {
  866.         if (kind == daWind) {
  867.             CloseDeskAcc(((WindowPeek)top)->windowKind);
  868.         } else {
  869.             (*dispatch->doClose)(top);
  870.         }
  871.         callHandlers = false;
  872.     } else if (theMenu == EditMenuID) {
  873.         callHandlers = !SystemEdit(theItem-1);
  874.     }
  875.     if (callHandlers) {
  876.         if (top && kind != daWind) {
  877.             callHandlers = !(*dispatch->doCommand)(top, theMenu, theItem);
  878.         }
  879.         if (callHandlers) {
  880.             for (i = 0; i < numCmdHandlers; i++) {
  881.                 if ((*(**CmdHandlers)[i])(nil, theMenu, theItem)) break;
  882.             }
  883.         }
  884.     }
  885.     HiliteMenu(0);
  886. }
  887.  
  888. /*_____________________________________________________________________
  889.  
  890.     oop_DoEvent - Process One Event.
  891.     
  892.     Entry        event = pointer to event record, or nil if oop_DoEvent should
  893.                     fetch the next event.
  894.                 eventMask = event mask for WaitNextEvent call.
  895.                 sleep = sleep time for WaitNextEvent call.
  896.                 mouseRgn = mouse region for WaitNextEvent call.
  897.     
  898.     A DoPeriodic message is dispatched to the top window object.
  899.     
  900.     The next event is fetched and the appropriate message is dispatched
  901.     to the appropriate window object.
  902. _____________________________________________________________________*/
  903.  
  904. void oop_DoEvent (EventRecord *event, short eventMask, long sleep, 
  905.     RgnHandle mouseRgn)
  906.  
  907. {
  908.     WindowPtr            top;                /* pointer to top window record */
  909.     short                    kind;                /* top window kind */
  910.     WindObj                **wobj;            /* handle to window object */
  911.     oop_Dispatch        *dispatch;        /* pointer to method dispatch table */
  912.     short                    partCode;        /* FindWindow part code */
  913.     WindowPtr            w;                    /* window clicked in */
  914.     Point                    where;            /* location of mouse click in local coords */
  915.     char                    key;                /* the key pressed */
  916.     Rect                    oldPortRect;    /* old window portrect */
  917.     Rect                    newPortRect;    /* new window portrect */
  918.     GrafPtr                savedPort;        /* saved grafport */
  919.     Boolean                wneResult;        /* WaitNextEvent function result */
  920.  
  921.     GetPort(&savedPort);
  922.     top = FrontWindow();
  923.     kind = oop_GetWindKind(top);
  924.     if (InForeground) (*DoPeriodic)(top);
  925.     if (top && kind != daWind) {
  926.         SetPort(top);
  927.         wobj = GetWindObj(top);
  928.         dispatch = (**wobj).dispatch;
  929.         if (InForeground) (*dispatch->doPeriodic)(top);
  930.     } else {
  931.         dispatch = nil;
  932.     }
  933.     if (event) {
  934.         Event = *event;
  935.         wneResult = true;
  936.     } else {
  937.         wneResult = utl_WaitNextEvent(eventMask, &Event, sleep, mouseRgn);
  938.     }
  939.     if (top && (**wobj).dialog) IsDialogEvent(&Event);
  940.     if (wneResult) {
  941.         switch (Event.what) {
  942.             case mouseDown:
  943.                 switch (partCode = FindWindow(Event.where, &w)) {
  944.                     case inSysWindow:
  945.                         SystemClick(&Event, w);
  946.                         break;
  947.                     case inMenuBar:
  948.                         DispatchCommand(top, kind, dispatch, MenuSelect(Event.where));
  949.                         break;
  950.                     case inGoAway:
  951.                         if (TrackGoAway(w, Event.where)) {
  952.                             (*dispatch->doClose)(w);
  953.                             InitCursor();
  954.                         }
  955.                     case inDrag:
  956.                         oldPortRect = newPortRect = w->portRect;
  957.                         SetPort(w);
  958.                         LocalToGlobal((Point*)&oldPortRect);
  959.                         DragWindow(w, Event.where, &DragRect);
  960.                         LocalToGlobal((Point*)&newPortRect);
  961.                         if (abs(oldPortRect.top - newPortRect.top) >= dragSlop ||
  962.                             abs(oldPortRect.left - newPortRect.left) >= dragSlop) 
  963.                                 (**wobj).moved = true;
  964.                         break;
  965.                     case inGrow:
  966.                         SetPort(w);
  967.                         oldPortRect = w->portRect;
  968.                         (*dispatch->doGrow)(w, Event.where);
  969.                         if (abs(oldPortRect.right - (w->portRect).right) >= dragSlop ||
  970.                             abs(oldPortRect.bottom - (w->portRect).bottom) >= dragSlop) 
  971.                                 (**wobj).moved = true;
  972.                         break;
  973.                     case inZoomIn:
  974.                     case inZoomOut:
  975.                         SetPort(w);
  976.                         oldPortRect = w->portRect;
  977.                         (*dispatch->doZoom)(w, Event.where, partCode);
  978.                         if (abs(oldPortRect.right - (w->portRect).right) >= dragSlop ||
  979.                             abs(oldPortRect.bottom - (w->portRect).bottom) >= dragSlop) 
  980.                                 (**wobj).moved = true;
  981.                         break;
  982.                     case inContent:
  983.                         if (w != top) {
  984.                             if (!(**wobj).modal) {
  985.                                 SelectWindow(w);
  986.                             } else {
  987.                                 SysBeep(0);
  988.                             }
  989.                         } else {
  990.                             SetPort(w);
  991.                             where = Event.where;
  992.                             GlobalToLocal(&where);
  993.                             (*dispatch->doClick)(w, where, Event.modifiers);
  994.                         }
  995.                         break;
  996.                 }
  997.                 break;
  998.             case keyDown:
  999.             case autoKey:
  1000.                 key = Event.message & charCodeMask;
  1001.                 if ((Event.modifiers & cmdKey) && key != '.') {
  1002.                     DispatchCommand(top, kind, dispatch, MenuKey(key));
  1003.                 } else {
  1004.                     if (dispatch) (*dispatch->doKey)(top, key, Event.modifiers);
  1005.                 }
  1006.                 break;
  1007.             case activateEvt:
  1008.                 w = (WindowPtr)Event.message;
  1009.                 SetPort(w);
  1010.                 wobj = GetWindObj(w);
  1011.                 dispatch = (**wobj).dispatch;
  1012.                 if (Event.modifiers & activeFlag) {
  1013.                     (*dispatch->doActivate)(w);
  1014.                 } else {
  1015.                     (*dispatch->doDeactivate)(w);
  1016.                 }
  1017.                 break;
  1018.             case updateEvt:
  1019.                 w = (WindowPtr)Event.message;
  1020.                 wobj = GetWindObj(w);
  1021.                 dispatch = (**wobj).dispatch;
  1022.                 SetPort(w);
  1023.                 BeginUpdate(w);
  1024.                 (*dispatch->doUpdate)(w);
  1025.                 EndUpdate(w);
  1026.                 break;
  1027.             case diskEvt:
  1028.                 if (DoDisk) (*DoDisk)(Event.message);
  1029.                 break;
  1030.             case osEvt:
  1031.                 if (((Event.message >> 24) & 0xff) != suspendResumeMessage) break;
  1032.                 InForeground = Event.message & 1;
  1033.                 if (InForeground) InitCursor();
  1034.                 if (dispatch) {
  1035.                     SetPort(top);
  1036.                     if (InForeground) {
  1037.                         (*dispatch->doActivate)(top);
  1038.                     } else {
  1039.                         (*dispatch->doDeactivate)(top);
  1040.                     }
  1041.                 }
  1042.                 break;
  1043.             case kHighLevelEvent:
  1044.                 AEProcessAppleEvent(&Event);
  1045.                 break;
  1046.         }
  1047.     }
  1048.     SetPort(savedPort);
  1049. }
  1050.  
  1051. /*_____________________________________________________________________
  1052.  
  1053.     oop_UpdateAll - Update All Windows.
  1054. _____________________________________________________________________*/
  1055.  
  1056. void oop_UpdateAll (void)
  1057.  
  1058. {
  1059.     WindowPtr        w;                /* traverses window list */
  1060.     WindowPeek        wp;            /* windowpeek pointer */
  1061.     WindObj            **wobj;        /* handle to window object */
  1062.     oop_Dispatch    *dispatch;    /* pointer to method dispatch table */
  1063.     GrafPtr            savedPort;    /* saved grafport */
  1064.     
  1065.     GetPort(&savedPort);
  1066.     w = FrontWindow();
  1067.     while (w) {
  1068.         if (oop_GetWindKind(w) != daWind) {
  1069.             wp = (WindowPeek)w;
  1070.             if (!EmptyRgn(wp->updateRgn)) {
  1071.                 SetPort(w);
  1072.                 wobj = GetWindObj(w);
  1073.                 dispatch = (**wobj).dispatch;
  1074.                 BeginUpdate(w);
  1075.                 (*dispatch->doUpdate)(w);
  1076.                 EndUpdate(w);
  1077.             }
  1078.         }
  1079.         w = (WindowPtr)(wp->nextWindow);
  1080.     }
  1081.     SetPort(savedPort);
  1082. }
  1083.  
  1084. /*_____________________________________________________________________
  1085.  
  1086.     oop_ModalUpdate - Update a Window in a Modal Dialog.
  1087.     
  1088.     Entry:    theDialog = pointer to modal dialog.
  1089.                 theEvent = pointer to event record.
  1090.                 
  1091.     Exit:        function result = false.
  1092.     
  1093.     This function should be used as a filter proc for all modal dialogs
  1094.     and alerts. It takes care of the "pending update peril" problem (see
  1095.     TN 304) which happens when a modal dialog is active and an update
  1096.     event occurs for some other window in the application.
  1097. _____________________________________________________________________*/
  1098.  
  1099. pascal Boolean oop_ModalUpdate (DialogPtr theDialog,
  1100.     EventRecord *theEvent, short *itemHit)
  1101.     
  1102. {
  1103. #pragma unused (itemHit)
  1104.  
  1105.     WindowPtr        w;                /* pointer to window to be updated */
  1106.     WindObj            **wobj;        /* handle to window object */
  1107.     oop_Dispatch    *dispatch;    /* pointer to method dispatch table */
  1108.     GrafPtr            savedPort;    /* saved grafport */
  1109.     
  1110.     w = (WindowPtr)theEvent->message;
  1111.     if (theEvent->what == updateEvt && w != theDialog && oop_GetWindKind(w) != daWind) {
  1112.         GetPort(&savedPort);
  1113.         SetPort(w);
  1114.         wobj = GetWindObj(w);
  1115.         dispatch = (**wobj).dispatch;
  1116.         BeginUpdate(w);
  1117.         (*dispatch->doUpdate)(w);
  1118.         EndUpdate(w);
  1119.         SetPort(savedPort);
  1120.     }
  1121.     return false;
  1122. }
  1123.